package com.duojuhe.coremodule.system.service.impl;

import com.duojuhe.cache.SystemDictCache;
import com.duojuhe.common.bean.UserTokenInfoVo;
import com.duojuhe.common.constant.SystemConstants;
import com.duojuhe.common.enums.SystemEnum;
import com.duojuhe.common.enums.user.UserEnum;
import com.duojuhe.common.exception.base.DuoJuHeException;
import com.duojuhe.common.result.ErrorCodes;
import com.duojuhe.common.result.ServiceResult;
import com.duojuhe.common.utils.idgenerator.UUIDUtils;
import com.duojuhe.common.utils.page.PageHelperUtil;
import com.duojuhe.common.utils.tree.TreeBaseBean;
import com.duojuhe.common.utils.tree.TreeUtil;
import com.duojuhe.coremodule.BaseService;
import com.duojuhe.coremodule.system.entity.SystemDict;
import com.duojuhe.coremodule.system.entity.SystemMenu;
import com.duojuhe.coremodule.system.entity.SystemRoleMenu;
import com.duojuhe.coremodule.system.entity.SystemTenantMenu;
import com.duojuhe.coremodule.system.mapper.SystemMenuMapper;
import com.duojuhe.coremodule.system.mapper.SystemRoleMenuMapper;
import com.duojuhe.coremodule.system.mapper.SystemTenantMenuMapper;
import com.duojuhe.coremodule.system.pojo.dto.menu.*;
import com.duojuhe.coremodule.system.service.SystemMenuService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Slf4j
@Service
public class SystemMenuServiceImpl extends BaseService implements SystemMenuService {
    @Resource
    private SystemDictCache systemDictCache;
    @Resource
    private SystemMenuMapper systemMenuMapper;
    @Resource
    private SystemRoleMenuMapper systemRoleMenuMapper;
    @Resource
    private SystemTenantMenuMapper systemTenantMenuMapper;

    /**
     * 根据菜单主键查询菜单详情数据
     */
    @Override
    public ServiceResult<QuerySystemMenuRes> querySystemMenuResByMenuId(SystemMenuIdReq req) {
        String menuId = req.getMenuId();
        QuerySystemMenuRes res = systemMenuMapper.querySystemMenuResByMenuId(menuId);
        setHandleSystemMenuDictNameColor(res);
        return ServiceResult.ok(res);
    }


    /**
     * 获取所有菜单资源【tree型结构】，一般用于菜单管理列表界面
     */
    @Override
    public ServiceResult<List<QuerySystemMenuTreeRes>> querySystemMenuTreeResList(QuerySystemMenuTreeReq req) {
        PageHelperUtil.defaultOrderBy("sort desc,createTime desc,menuId desc");
        List<QuerySystemMenuTreeRes> menuList = systemMenuMapper.querySystemMenuTreeResList(req);
        menuList.forEach(this::setHandleSystemMenuDictNameColor);
        List<TreeBaseBean> tList = TreeUtil.treeList(menuList);
        return ServiceResult.ok(tList);
    }

    /**
     * 【租户绑定菜单权限-查询tree型结构】获取状态是可用的菜单资源，一般用于租户绑定菜单使用【包含功能按钮类型】
     * @return
     */
    @Override
    public ServiceResult<List<SelectSystemMenuTreeRes>> queryTenantBindingUseMenuTreeResList() {
        //排序
        PageHelperUtil.defaultOrderBy("sort desc,createTime desc,menuId desc");
        //租户管理人员
        List<SelectSystemMenuTreeRes> menuList = systemMenuMapper.querySystemTenantNormalSystemMenuTreeResListByTenantId(StringUtils.EMPTY);
        List<TreeBaseBean> tList = TreeUtil.treeList(menuList);
        return ServiceResult.ok(tList);
    }

    /**
     * 获取所有菜单资源【tree型结构】，一般用于角色绑定权限使用【包含功能按钮类型】
     */
    @Override
    public ServiceResult<List<SelectSystemMenuTreeRes>> querySelectNormalSystemMenuTreeResListByMenuType(String menuType) {
        //待返回的菜单
        List<SelectSystemMenuTreeRes> menuList = new ArrayList<>();
        //当前登录人
        UserTokenInfoVo userTokenInfoVo = getCurrentLoginUserInfoDTO();
        //用户类型
        String userTypeCode = userTokenInfoVo.getUserTypeCode();
        //排序
        PageHelperUtil.defaultOrderBy("sort desc,createTime desc,menuId desc");
        if (UserEnum.USER_TYPE.SUPER_ADMIN.getKey().equals(userTypeCode)){
            //超管用户
            menuList = systemMenuMapper.queryNormalSystemMenuTreeResListByMenuTypeOrRoleId(menuType,"");
        }else if (UserEnum.USER_TYPE.TENANT_ADMIN.getKey().equals(userTypeCode)){
            //租户管理人员
            menuList = systemMenuMapper.querySystemTenantNormalSystemMenuTreeResListByTenantId(userTokenInfoVo.getTenantId());
        }else {
            //常规普通用户
            String roleId = StringUtils.isBlank(userTokenInfoVo.getRoleId())? SystemConstants.UNKNOWN_ID:userTokenInfoVo.getRoleId();
            menuList = systemMenuMapper.queryNormalSystemMenuTreeResListByMenuTypeOrRoleId(menuType,roleId);
        }
        List<TreeBaseBean> tList = TreeUtil.treeList(menuList);
        return ServiceResult.ok(tList);
    }


    /**
     * 保存admin菜单
     */
    @Override
    public ServiceResult saveSystemMenu(SaveSystemMenuReq req) {
        //菜单code
        String menuCode = req.getMenuCode();
        //默认为顶级菜单，用-1标识
        String parentId = getParentSystemMenuIdByParentId(req.getParentId(),req.getMenuTypeCode());
        //检查菜单编码是否存在
        checkSystemMenuCode(menuCode);
        //当前时间
        Date date = new Date();
        //菜单id
        String menuId = UUIDUtils.getUUID32();
        //构建菜单对象
        SystemMenu menu = new SystemMenu();
        menu.setMenuId(menuId);
        menu.setParentId(parentId);
        menu.setMenuName(req.getMenuName());
        menu.setMenuCode(menuCode);
        menu.setApiUrl(req.getApiUrl());
        menu.setBuiltIn(SystemEnum.YES_NO.NO.getKey());
        menu.setMenuCacheCode(SystemEnum.YES_NO.NO.getKey());
        menu.setMenuFrameCode(req.getMenuFrameCode());
        menu.setTenantMenu(req.getTenantMenu());
        menu.setStatusCode(req.getStatusCode());
        menu.setSort(req.getSort());
        menu.setCreateTime(date);
        menu.setUpdateTime(date);
        menu.setMenuIcon(req.getMenuIcon());
        menu.setComponent(req.getComponent());
        menu.setMenuTypeCode(req.getMenuTypeCode());
        menu.setRemark(req.getRemark());
        menu.setDescription(req.getDescription());
        systemMenuMapper.insertSelective(menu);
        return ServiceResult.ok(menuId);
    }



    /**
     * 修改admin菜单
     */
    @Override
    public ServiceResult updateSystemMenu(UpdateSystemMenuReq req) {
        SystemMenu systemMenuOld = systemMenuMapper.selectByPrimaryKey(req.getMenuId());
        if (systemMenuOld == null) {
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        if (SystemEnum.YES_NO.YES.getKey().equals(systemMenuOld.getBuiltIn())) {
            return ServiceResult.fail(ErrorCodes.BUILT_IN_MENU_NOT_UPDATE);
        }
        //导航菜单标识
        String navigation = SystemEnum.MENU_TYPE.NAVIGATION.getKey();
        //功能按钮标识
        String button = SystemEnum.MENU_TYPE.BUTTON.getKey();
        //默认为顶级菜单，用-1标识
        String parentId = getParentSystemMenuIdByParentId(req.getParentId(),req.getMenuTypeCode());
        //当菜单编码改变了，检查一下编码是已否存在
        if (!req.getMenuCode().equals(systemMenuOld.getMenuCode())) {
            checkSystemMenuCode(req.getMenuCode());
        }
        if (systemMenuOld.getMenuId().equals(parentId)) {
            return ServiceResult.fail(ErrorCodes.PARENT_MENU_NOT_SELF);
        }
        if (!StringUtils.equals(SystemConstants.UNKNOWN_ID, parentId)) {
            if (checkChildren(parentId, systemMenuOld.getMenuId())) {
                return ServiceResult.fail(ErrorCodes.PARENT_MENU_NOT_SELF_CHILDREN);
            }
        }
        if (checkSystemMenuChildren(systemMenuOld.getMenuId(), navigation)&& button.equals(req.getMenuTypeCode())) {
            return ServiceResult.fail(ErrorCodes.EXIST_CHILDREN_MENU_TYPE_NOT_FUNCTION);
        }
        //当前时间
        Date date = new Date();
        SystemMenu menu = new SystemMenu();
        menu.setMenuId(systemMenuOld.getMenuId());
        menu.setParentId(parentId);
        menu.setMenuName(req.getMenuName());
        menu.setMenuCode(req.getMenuCode());
        menu.setApiUrl(req.getApiUrl());
        menu.setStatusCode(req.getStatusCode());
        menu.setSort(req.getSort());
        menu.setUpdateTime(date);
        menu.setMenuIcon(req.getMenuIcon());
        menu.setComponent(req.getComponent());
        menu.setMenuTypeCode(req.getMenuTypeCode());
        menu.setMenuFrameCode(req.getMenuFrameCode());
        menu.setRemark(req.getRemark());
        menu.setDescription(req.getDescription());
        menu.setTenantMenu(req.getTenantMenu());
        systemMenuMapper.updateByPrimaryKeySelective(menu);
        return ServiceResult.ok(req.getMenuId());
    }

    /**
     * 根据主键删除菜单
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ServiceResult deleteSystemMenuByMenuId(SystemMenuIdReq req) {
        //菜单id
        String menuId = req.getMenuId();
        //查询对象
        SystemMenu systemMenu = systemMenuMapper.selectByPrimaryKey(menuId);
        if (systemMenu == null) {
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        if (SystemEnum.YES_NO.YES.getKey().equals(systemMenu.getBuiltIn())) {
            return ServiceResult.fail(ErrorCodes.BUILT_IN_MENU_NOT_DELETE);
        }
        if (checkSystemMenuChildren(menuId, null)) {
            return ServiceResult.fail(ErrorCodes.EXIST_CHILDREN_MENU_NOT_DELETE);
        }
        //删除该菜单之前的所有关联的角色
        SystemRoleMenu roleFunction = new SystemRoleMenu();
        roleFunction.setMenuId(menuId);
        systemRoleMenuMapper.delete(roleFunction);
        //删除菜单关联的租户功能
        SystemTenantMenu tenantMenu = new SystemTenantMenu();
        tenantMenu.setMenuId(menuId);
        systemTenantMenuMapper.delete(tenantMenu);
        //删除菜单主表
        systemMenuMapper.deleteByPrimaryKey(menuId);
        return ServiceResult.ok(menuId);
    }


    /*====================================私有方法beg================================================**/
    /**
     * 获取父级id
     * @param reqParentId
     * @param menuTypeCode
     * @return
     */
    private String getParentSystemMenuIdByParentId(String reqParentId,String menuTypeCode){
        //导航菜单标识
        String navigation = SystemEnum.MENU_TYPE.NAVIGATION.getKey();
        //功能按钮标识
        String button = SystemEnum.MENU_TYPE.BUTTON.getKey();
        //默认父级id
        String parentId = SystemConstants.UNKNOWN_ID;
        if (!StringUtils.equals(parentId, reqParentId)) {
            SystemMenu parentMenu = systemMenuMapper.selectByPrimaryKey(reqParentId);
            if (parentMenu == null) {
                throw new DuoJuHeException(ErrorCodes.PARENT_PARAM_ERROR);
            }
            if (button.equals(parentMenu.getMenuTypeCode())) {
                throw new DuoJuHeException(ErrorCodes.PARENT_MENU_TYPE_NOT_FUNCTION);
            }
            //父级id
            parentId = reqParentId;
            if (checkSystemMenuChildren(parentId, navigation)&&button.equals(menuTypeCode)) {
                throw new DuoJuHeException(ErrorCodes.EXIST_CHILDREN_MENU_TYPE_NOT_FUNCTION);
            }
        }
        if (parentId.equals(SystemConstants.UNKNOWN_ID) && button.equals(menuTypeCode)) {
            throw new DuoJuHeException(ErrorCodes.PARENT_MENU_TYPE_NOT_FUNCTION);
        }
        return  parentId;
    }

    /**
     * 【私有方法，辅助其他接口方法使用】 查找该节点下面是否存在子节点
     */
    private boolean checkSystemMenuChildren(String parentId, String menuTypeCode) {
        Example example = new Example(SystemMenu.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("parentId", parentId);
        if (StringUtils.isNotBlank(menuTypeCode)) {
            criteria.andEqualTo("menuTypeCode", menuTypeCode);
        }
        return systemMenuMapper.selectByExample(example).size()>0;
    }

    /**
     * 【私有方法，辅助其他接口方法使用】 查询菜单code编码是否已经存在
     */
    private void checkSystemMenuCode(String menuCode) {
        Example example = new Example(SystemMenu.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("menuCode", menuCode);
        if(systemMenuMapper.selectByExample(example).size()>0){
            throw new DuoJuHeException(ErrorCodes.MENU_CODE_EXIST);
        }
    }


    /**
     * 【私有方法，辅助其他接口方法使用】 检测所选项是不是当前id的子项
     */
    private boolean checkChildren(String menuId, String parentId) {
        if (StringUtils.isBlank(menuId)){
            return true;
        }
        SystemMenu menu = systemMenuMapper.selectByPrimaryKey(menuId);
        String newPid = menu.getParentId();
        if (newPid.equals(parentId)) {
            return true;
        } else {
            if (!StringUtils.equals(newPid, SystemConstants.UNKNOWN_ID)
                    && !StringUtils.equals(newPid, parentId)) {
                checkChildren(parentId, newPid);
            }
        }
        return false;
    }

    /**
     * 处理返回值的数据字典
     * @param res
     */
    private void setHandleSystemMenuDictNameColor(HandleSystemMenuDictNameColorRes res) {
        if (res==null){
            return;
        }
        SystemDict dictBuiltIn = systemDictCache.getSystemDictByDictCode(res.getBuiltIn());
        res.setBuiltInName(dictBuiltIn.getDictName());
        res.setBuiltInColor(dictBuiltIn.getDictColor());

        SystemDict dictStatus = systemDictCache.getSystemDictByDictCode(res.getStatusCode());
        res.setStatusName(dictStatus.getDictName());
        res.setStatusColor(dictStatus.getDictColor());

        SystemDict menuType = systemDictCache.getSystemDictByDictCode(res.getMenuTypeCode());
        res.setMenuTypeColor(menuType.getDictColor());
        res.setMenuTypeName(menuType.getDictName());
    }
    /*====================================私有方法end================================================**/
}
